﻿//////////////////////////////////////////////////////////////////////////////
//
// Copyright © 1998-2024 Glodon Company Limited.
//
// Licensed under the MIT License
//
// Permission is hereby granted, free of charge, to any person obtaining a
// copy of this software and associated documentation files (the “Software”),
// to deal in the Software without restriction, including without limitation
// the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
// sell copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
//
//////////////////////////////////////////////////////////////////////////////
// std headers
#include "TranslatorManager.h"
#include <algorithm>

// qt headers
#include <QString>
#include <qmath.h>
#include <QRegExp>

// custom headers
#include "IParameter.gcs.h"
#include "GmepParameterUtils.h"
#include "IParameterDefinition.gcs.h"
#include "DebugMessage.h"

#include "EnableCompileWarning_The_LAST_IncludeInCpp.h" 

namespace gmepgcs
{
    IParameter::IParameter() : 
        m_isValueSpecified(false)
    {
    }

    IParameter::~IParameter()
    {
    }

    bool IParameter::operator==(const IParameter & other)
    {
        // compare value
        if (Definition)
        {
            if (Definition->GetParameterType() == L"Integer")
            {
                auto flag = true;
                auto intValue = QString::fromStdWString(Value).toInt(&flag);
                auto otherIntValue = QString::fromStdWString(other.Value).toInt(&flag);
                if (flag)
                {
                    if (intValue != otherIntValue)
                    {
                        return false;
                    }
                }
                else
                {
                    if (Value != other.Value)
                    {
                        return false;
                    }
                }
            }
            else if (Definition->GetParameterType() == L"Double")
            {
                auto flag = true;
                auto doubleValue = QString::fromStdWString(Value).toDouble(&flag);
                auto otherDoubleValue = QString::fromStdWString(other.Value).toDouble(&flag);
                if (flag)
                {
                    if ((abs(doubleValue - otherDoubleValue) > 0.000001))
                    {
                        return false;
                    }
                }
                else
                {
                    if (Value != other.Value)
                    {
                        return false;
                    }
                }
            }
            else
            {
                if (Value != other.Value)
                {
                    return false;
                }
            }
        }
        else
        {
            if (Value != other.Value)
            {
                return false;
            }
        }

        // compare definition
        if ((nullptr == Definition) && (nullptr == other.Definition))
        {
            return false;
        }
        else if ((nullptr != Definition) && (nullptr != other.Definition))
        {
            if (*(Definition) != *(other.Definition))
            {
                return false;
            }
        }
        else
        {
            return false;
        }

        return true;
    }

    bool IParameter::operator!=(const IParameter & other)
    {
        return !operator==(other);
    }

    // 没有使用暂时注释
    //std::shared_ptr<IParameter> IParameter::Clone()
    //{
    //    std::shared_ptr<IParameter> spClone = std::make_shared<IParameter>();
    //    DBG_WARN_AND_RETURN_NULLPTR_UNLESS(spClone, L"spClone 为空", L"GMEP", L"2024-01-30");
    //    spClone->Value = Value;

    //    spClone->Definition =
    //        nullptr == Definition
    //        ? nullptr
    //        : Definition->Clone();

    //    spClone->SetIsValueSpecified(IsValueSpecified());

    //    return spClone;
    //}

    std::shared_ptr<IParameter> IParameter::CloneWithExternalParameterDefinition(const std::map<std::wstring, std::shared_ptr<IParameterDefinition>>& availableParameterDefinitions)
    {
        std::shared_ptr<IParameter> spClone = std::make_shared<IParameter>();
        DBG_WARN_AND_RETURN_NULLPTR_UNLESS(spClone, L"spClone 为空", L"GMEP", L"2024-01-30");
        spClone->Value = Value;

        // clone definition
        if (nullptr == Definition)
        {
            spClone->Definition = nullptr;
        }
        else
        {
            auto availableDefinitonIterator = availableParameterDefinitions.find(Definition->GetName());
            if (availableDefinitonIterator != availableParameterDefinitions.end())
            {
                spClone->Definition = availableDefinitonIterator->second;
            }
            else
            {
                spClone->Definition = nullptr;
            }
        }

        spClone->SetIsValueSpecified(IsValueSpecified());

        return spClone;
    }

    bool IParameter::IsVisible()
    {
        if (!Definition)
        {
            return false;
        }

        return Definition->IsVisible();
    }

    bool IParameter::IsDeleteable()
    {
        if (!Definition)
        {
            return false;
        }
        
        return Definition->IsDeleteable();
    }

    bool IParameter::IsNameEditable()
    {
        if (!Definition)
        {
            return false;
        }

        return Definition->IsNameEditable();
    }

    bool IParameter::IsValueEditable()
    {
        if (!Definition)
        {
            return false;
        }

        //后续方案支持使用属性配置xml中属性判断可编辑后，不再使用这个方法判断
        //设备零件参数与管件零件参数不可修改
        if (!gmep::GmepParameterUtils::IsParameterEditable(Definition->GetId()))
        {
            return false;
        }

        // 对于几何参数
        if (Definition->IsGeometry())
        {
            // 当参数是几何参数、是驱动参数、且不是被驱动参数时，可修改值
            if (Definition->GetIsDrivingParameter() && !Definition->GetIsOutputParameter())
            {
                return true;
            }
            
            // 当参数是几何参数、且既非驱动参数、也非被驱动参数时，可修改值            
            if (!Definition->GetIsDrivingParameter() && !Definition->GetIsOutputParameter())
            {
                return true;
            }
        }

        // 对于标准参数
        if (Definition->GetIsStandard())
        {
            return true;
        }

        // 对于自定义参数
        if (!Definition->IsGeometry() && !Definition->GetIsStandard())
        {
            // 当参数时自定义参数、且不是被驱动参数时，可修改值
            if (!Definition->GetIsOutputParameter())
            {
                return true;
            }
        }

        return false;
    }

    bool IParameter::IsUnitEditable()
    {
        if (!Definition)
        {
            return false;
        }

        return Definition->IsUnitEditable();
    }

    bool IParameter::IsInstanceEditable()
    {
        if (!Definition)
        {
            return false;
        }

        return Definition->IsInstanceEditable();
    }
    
    bool IParameter::IsValueSpecified()
    {
        return m_isValueSpecified;
    }

    void IParameter::SetIsValueSpecified(bool isValueSpecified)
    {
        if (m_isValueSpecified != isValueSpecified)
        {
            m_isValueSpecified = isValueSpecified;
        }
    }

    std::vector<std::pair<std::wstring, std::wstring>> IParameter::GetEnumValues() const
    {
        std::vector<std::pair<std::wstring, std::wstring>> enumValues;
        if (Definition)
        {
            for (auto &item : Definition->GetValues())
            {
                enumValues.push_back(std::pair<std::wstring, std::wstring>(item.first, item.second));
            }
        }

        return enumValues;
    }
    
    std::vector<std::pair<std::wstring, std::wstring>> IParameter::s_vLogicValues = std::vector<std::pair<std::wstring, std::wstring>>();
    std::vector<std::pair<std::wstring, std::wstring>> IParameter::GetLogicValues()
    {
        if (IParameter::s_vLogicValues.empty())
        {
            IParameter::s_vLogicValues.push_back(std::pair<std::wstring, std::wstring>(L"true", GBMP_TR(L"是")));
            IParameter::s_vLogicValues.push_back(std::pair<std::wstring, std::wstring>(L"false", GBMP_TR(L"否")));
        }
        return IParameter::s_vLogicValues;
    }

    std::wstring IParameter::GetLogicStorageStr(const bool & boolValue)
    {        
        return boolValue? L"true" : L"false";
    }

    std::wstring IParameter::GetDisplayValue() const
    {
        if (!Definition)
        {
            return Value;
        }

        if (Definition->GetValueType() == L"Enum")
        {
            auto found = Definition->GetValues().find(Value);
            if (found != Definition->GetValues().end())
            {
                return (*found).second;
            }
        }
        else if (Definition->GetValueType() == L"Logic")
        {
            auto &logicVlaues = IParameter::GetLogicValues();
            auto value = QString::fromStdWString(Value).trimmed().toLower().toStdWString();
            auto found = std::find_if(logicVlaues.begin(), logicVlaues.end(), 
                [value](const std::vector<std::pair<std::wstring, std::wstring>>::value_type &item) {
                return item.first == value;
            });

            if (found != logicVlaues.end())
            {
                return (*found).second;
            }
        }

        if (Definition->GetParameterDisplayType() == L"Angle")
        {
            auto strRadvalue = QString::fromStdWString(Value).trimmed();
            if (!strRadvalue.isEmpty())
            {
                auto ok = false;
                auto doubleRadValue = strRadvalue.toDouble(&ok);
                if (ok)
                {
                    auto doubleDegValue = doubleRadValue * 180.0 / M_PI;
                    QRegExp redundantZeros;
                    redundantZeros.setPattern("(\\.){0,1}0+$");
                    auto strDegValue = QString("%1").arg(doubleDegValue, 0, 'f', 2).replace(redundantZeros, "").toStdWString();
                    return strDegValue;
                }
            }
        }

        return Value;
    }

    bool IParameter::SetValue(const std::wstring &value)
    {
        if (Value == value)
        {
            return true;
        }

        if (!Definition)
        {
            Value = value;
            return true;
        }
        
        if (Definition->GetValueType() == L"Enum")
        {
            if (Definition->GetValues().empty())
            {
                Value = std::wstring();
                return false;
            }

            auto foundEnumValueIterator = Definition->GetValues().find(value);
            if (foundEnumValueIterator == Definition->GetValues().end())
            {
                Value = std::wstring();
                return false;
            }

            Value = value;
            return true;
        }
        else
        {
            Value = value;
            return true;
        }
    }

}
